import type { JSONSchema6, JSONSchema6Definition } from 'json-schema';

// eslint-disable-next-line @typescript-eslint/ban-types
type AnyObject = {};

export type JsonSchemaProperty = JSONSchema6Definition & {
  // 允许加入其他的一些属性声明，不然太死板了
  [k: string]: unknown,
};

// type AjvSchemaProperties<T extends AnyObject> = PropertiesSchema<T>
export type JsonSchemaProperties<T extends AnyObject> = {
  [k in keyof T]: JsonSchemaProperty;
} & {
  [k: string]: JsonSchemaProperty;
}

type JsonSchemaRequired<T extends AnyObject> = Readonly<(keyof T | string)[]>

export type JsonSchemaOtherDef = Omit<JSONSchema6, 'type' | 'properties' | 'required' | 'additionalProperties'>

const isSchemaDef = (x: unknown): x is JsonSchemaOtherDef => typeof x === 'object';

export function schemaObject<T extends AnyObject = AnyObject>(
  properties: Partial<JsonSchemaProperties<T>>,
  required: JsonSchemaRequired<T> = [],
  additionalProperties?: boolean | Partial<JsonSchemaOtherDef>,
  schema?: Partial<JsonSchemaOtherDef>,
): JSONSchema6 {
  if (additionalProperties == null) {
    additionalProperties = false;
  } else if (isSchemaDef(additionalProperties)) {
    schema = additionalProperties;
    additionalProperties = false;
  }
  return {
    type    : 'object',
    properties: properties as {
      [k: string]: JSONSchema6Definition;
    },
    required: required as string[],
    additionalProperties,
    ...schema,
  };
}

export const jsonSchemaObject = schemaObject;
